package com.jielin.handling.service.material.impl;

import com.jielin.handling.entity.material.MaterialFile;
import com.jielin.handling.entity.material.MaterialPack;
import com.jielin.handling.entity.material.MaterialPackVo;
import com.jielin.handling.entity.material.MaterialType;
import com.jielin.handling.entity.vo.material.MaterialTypeDocumentVo;
import com.jielin.handling.exception.ResultEnum;
import com.jielin.handling.mapper.material.MaterialFileMapper;
import com.jielin.handling.mapper.material.MaterialPackMapper;
import com.jielin.handling.mapper.material.MaterialTypeDocumentMapper;
import com.jielin.handling.mapper.material.MaterialTypeMapper;
import com.jielin.handling.service.material.MaterialPackService;
import com.jielin.handling.service.xsky.XskyService;
import com.jielin.handling.util.ConstantUtil;
import com.jielin.handling.util.StringUtil;
import com.jielin.handling.util.ZipUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import java.io.*;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

@Service
@Slf4j
public class MaterialPackServiceImpl implements MaterialPackService {
    @Autowired
    private MaterialPackMapper materialPackMapper;
    @Autowired
    private MaterialTypeMapper mTypeMapper;
    @Autowired
    private MaterialFileMapper mFileMapper;
    @Autowired
    private MaterialTypeDocumentMapper mTypeDocumentMapper;
    @Autowired
    private XskyService xskyService;

    @Override
    public MaterialPack fileZip(String casecode, String caseSuspectId, String policeid, String[] folders) {
        MaterialPack mp = null;
        if (StringUtil.isEmpty(casecode) || StringUtil.isEmpty(caseSuspectId) || StringUtil.isEmpty(policeid)) {
            return mp;
        } else if (folders == null || folders.length <= 0) {
            return mp;
        } else {
            List<MaterialType> mtlist = mTypeMapper.findMaterialByCaseCode(casecode, caseSuspectId, policeid, 0);
            // 查询已删除的文件录像信息
            List<String> deleteFileList = mTypeMapper.findDeleteFileList(casecode, caseSuspectId, policeid, 0, 1);
            if (mtlist.size() == 0) {
                return mp;// 一级文件目录没有东西
            } else {
                // 创建一级文件夹存放路径==》 案件名称-警员id-案件编号/嫌疑人姓名/一级目录名称
                String path = ConstantUtil.FILE_PATH + mtlist.get(0).getCasename() + "-"
                        + mtlist.get(0).getUploadpoliceid() + "-" + mtlist.get(0).getCasecode() + File.separator
                        + mtlist.get(0).getCaseSuspectName();
                String zipPath = ConstantUtil.FILEZIP_PATH + mtlist.get(0).getCasename() + "-"
                        + mtlist.get(0).getUploadpoliceid() + "-" + mtlist.get(0).getCasecode() + "（"
                        + mtlist.get(0).getCaseSuspectName() + "）";

                log.info("fileZip===>1.判断要压缩的文件是否存在");
                // 1. 判断要压缩的文件是否存在
                File file = new File(path);
                // 传过来的文件名字
                List<String> folderslist = Arrays.asList(folders);

                // 2. 加入要打包集合
                if (!file.exists()) {
                    log.info("fileZip===> 没有可打包的文件（没有相同名称的文件）");
                    return null;
                }

                // 压缩包的文件夹
                File zipFile = new File(zipPath);
                if (!zipFile.exists()) {
                    zipFile.mkdirs();
                }

                // 装所有打包的文件的集合(只有文件)
                List<File> listfile;
                // 递归遍历获取包含的文件
                log.info("fileZip===> 2. 加入要打包集合");
                listfile = getFileList(file, folderslist, new ArrayList<>());

                // 将集合转为数组
                File[] srcFiles = new File[listfile.size()];
                srcFiles = listfile.toArray(srcFiles);

                try {
                    for (int i = 0; i < srcFiles.length; i++) {// 复制要打包的文件到压缩目录下
                        String srcpath = srcFiles[i].getPath();// 源文件路径

                        int lennn = ConstantUtil.FILE_PATH.length();// 获取头的长度
                        String tarpath = srcpath.substring(lennn);// 源文件去掉头
//						String asd = tarpath.substring(0, tarpath.indexOf(srcFiles[i].getName()));// 源文件去掉尾巴文件名
                        String asd2 = tarpath.replace(
                                File.separator + mtlist.get(0).getCaseSuspectName() + File.separator,
                                "（" + mtlist.get(0).getCaseSuspectName() + "）" + File.separator);// 源文件去掉尾巴文件名
                        // 创建压缩的文件夹
                        File zipFilepath = new File(ConstantUtil.FILEZIP_PATH + asd2);
                        if (!zipFilepath.exists()) {
                            zipFilepath.mkdirs();
                        }
                        String truetarpath = ConstantUtil.FILEZIP_PATH + asd2;// 拼接压缩路径的头
                        if (srcFiles[i].isDirectory()) {
                            copyDirectiory(srcpath, truetarpath, deleteFileList);// 复制文件夹
                        } else {
                            copyFile(srcFiles[i], new File(truetarpath), deleteFileList);// 复制文件
                        }

                    }
                } catch (Exception e) {
                    log.info("fileZip===> 复制要打包的文件到压缩目录下方法报错:{}", e);
                    return null;
                }
                // 3. 拼接压缩包的路径
                String zipRealPath = zipPath + ".zip";
                // 调用压缩方法
                log.info("fileZip===> 调用压缩方法");
                try {
                    ZipUtil.toZip(zipPath, new FileOutputStream(zipRealPath), true);
                } catch (Exception e) {
                    log.info("fileZip===> 调用压缩方法报错:{}", e);
                }

                mp = new MaterialPack();
                mp.setId(StringUtil.generatorUUID());
                mp.setPackname(mtlist.get(0).getCasename() + "-" + mtlist.get(0).getUploadpoliceid() + "-"
                        + mtlist.get(0).getCasecode() + "（" + mtlist.get(0).getCaseSuspectName() + "）");
                mp.setUrl(zipRealPath);
                mp.setCasecode(casecode);
                mp.setPackpoliceid(policeid);
                // 6.将压缩包文件信息存入数据库
                materialPackMapper.addMateriaPack(mp);// 添加打包信息
            }
        }
        return mp;
    }

    // 复制文件
    public static void copyFile(File sourceFile, File targetFile, List<String> deleteFileList) throws IOException {
        for (String deleteFileName : deleteFileList) {
            if (sourceFile.getName().indexOf(deleteFileName) > -1) {// 如果包含已删除的文件名字
                return;
            }
        }
        // 新建文件输入流并对它进行缓冲
        FileInputStream input = new FileInputStream(sourceFile);
        BufferedInputStream inBuff = new BufferedInputStream(input);

        // 新建文件输出流并对它进行缓冲
        FileOutputStream output = new FileOutputStream(targetFile);
        BufferedOutputStream outBuff = new BufferedOutputStream(output);

        // 缓冲数组
        byte[] b = new byte[1024 * 5];
        int len;
        while ((len = inBuff.read(b)) != -1) {
            outBuff.write(b, 0, len);
        }
        // 刷新此缓冲的输出流
        outBuff.flush();

        // 关闭流
        inBuff.close();
        outBuff.close();
        output.close();
        input.close();
    }

    // 复制文件夹
    public static void copyDirectiory(String sourceDir, String targetDir, List<String> deleteFileList)
            throws IOException {
        // 新建目标目录
        (new File(targetDir)).mkdirs();
        // 获取源文件夹当前下的文件或目录
        File[] file = (new File(sourceDir)).listFiles();
        for (int i = 0; i < file.length; i++) {
            if (file[i].isFile()) {
                // 源文件
                File sourceFile = file[i];
                // 目标文件
                File targetFile = new File(new File(targetDir).getAbsolutePath() + File.separator + file[i].getName());
                copyFile(sourceFile, targetFile, deleteFileList);
            }
            if (file[i].isDirectory()) {
                // 准备复制的源文件夹
                String dir1 = sourceDir + File.separator + file[i].getName();
                // 准备复制的目标文件夹
                String dir2 = targetDir + File.separator + file[i].getName();
                copyDirectiory(dir1, dir2, deleteFileList);
            }
        }
    }

    // 该文件目录下文件全部放入数组
    public List<File> getFileList(File dir, List<String> listfileordir, List<File> filelist) {
        File[] files = dir.listFiles(); // 该文件目录下文件全部放入数组

        if (files != null) {
            for (int i = 0; i < files.length; i++) {
                if (listfileordir.contains(files[i].getName())) { // 判断是文件还是文件夹,是否包含该文件
                    filelist.add(files[i]);
                    continue;
                } else if (files[i].isDirectory()) {
                    getFileList(new File(files[i].getPath()), listfileordir, filelist); // 获取文件绝对路径
                } else {
                    continue;
                }
            }
        }
        return filelist;
    }

    @Override
    public List<MaterialPack> findAllMaterialPackInfo(String policeId, String keyWord, String isDownload) {
        if (StringUtil.isEmpty(policeId)) {
            return null;
        }
        return materialPackMapper.findAllMaterialPackInfo(policeId, keyWord, isDownload);
    }

    @Override
    public int updateMateriaPack(String id) {
        if (StringUtil.isEmpty(id)) {
            return -1;
        }
        return materialPackMapper.updateMateriaPack(id);
    }

    @Override
    public String findUrlById(String packId) {
        if (StringUtil.isEmpty(packId)) {
            return "";
        }
        materialPackMapper.updateMateriaPackDownloadCount(packId);// 更新下载次数
        return materialPackMapper.findUrlById(packId);
    }

    @Override
    public MaterialPack fileZipTwo(String materialTypeId, String documentId) {
        MaterialPack mp = null;
        if (!StringUtil.isEmpty(materialTypeId)) {// 第一种情况：只有卷宗一级id
            String[] materialTypeIds = materialTypeId.split(",");
            List<MaterialType> mtList = mTypeMapper.findByIds(materialTypeIds);
            if (mtList.size() > 0) {
                String zipPath = ConstantUtil.FILEZIP_PATH + mtList.get(0).getCasename() + "-"
                        + mtList.get(0).getUploadpoliceid() + "-" + mtList.get(0).getCasecode() + "（"
                        + mtList.get(0).getCaseSuspectName() + "）";
                for (MaterialType mt : mtList) {
                    // 获取一级文件夹存放路径==》 案件名称-警员id-案件编号/嫌疑人姓名/一级目录名称
                    String thisPath = ConstantUtil.FILE_PATH + mt.getCasename() + "-" + mt.getUploadpoliceid() + "-"
                            + mt.getCasecode() + File.separator + mt.getCaseSuspectName() + File.separator
                            + mt.getMaterialtypename();
                    String thisZipPath = ConstantUtil.FILEZIP_PATH + mt.getCasename() + "-" + mt.getUploadpoliceid()
                            + "-" + mt.getCasecode() + "（" + mt.getCaseSuspectName() + "）" + File.separator
                            + mt.getMaterialtypename();
                    // 1. 判断要压缩的文件是否存在
                    File file = new File(thisPath);

                    // 2. 复制到打包压缩的目录
                    if (file.exists()) {
                        log.info("fileZipTwo===> 打包的文件夹" + thisPath);
                        try {
                            copyDirectiory(thisPath, thisZipPath, null);
                        } catch (Exception e) {
                            log.info("fileZipTwo===> 复制要打包的文件到压缩目录下方法报错:{}", e);
                            return null;
                        }
                    }
                }
                // 3. 拼接压缩包的路径
                String zipRealPath = zipPath + ".zip";
                try {
                    ZipUtil.toZip(zipPath, new FileOutputStream(zipRealPath), true);
                } catch (Exception e) {
                    log.info("fileZip===> 调用压缩方法报错:{}", e);
                }
                mp = new MaterialPack();
                mp.setId(StringUtil.generatorUUID());
                mp.setPackname(mtList.get(0).getCasename() + "-" + mtList.get(0).getUploadpoliceid() + "-"
                        + mtList.get(0).getCasecode() + "（" + mtList.get(0).getCaseSuspectName() + "）");
                mp.setUrl(zipRealPath);
                mp.setCasecode(mtList.get(0).getCasecode());
                mp.setPackpoliceid(mtList.get(0).getUploadpoliceid());
                // 6.将压缩包文件信息存入数据库
                materialPackMapper.addMateriaPack(mp);// 添加打包信息
            }
        }
        if (!StringUtil.isEmpty(documentId)) {// 第二种情况：只有卷宗二级文件夹id

            String[] documentIds = documentId.split(",");
            List<MaterialFile> mfList = mFileMapper.findFileByDocumentIds(documentIds);
            if (mfList.size() > 0) {
                MaterialType mt = mTypeMapper.findByDocumentId(documentIds[0]);
                // 压缩文件的路径
                String zipPath = ConstantUtil.FILEZIP_PATH + mt.getCasename() + "-" + mt.getUploadpoliceid() + "-"
                        + mt.getCasecode() + "（" + mt.getCaseSuspectName() + "）";
                for (MaterialFile mf : mfList) {
                    File file = new File(mf.getUrl());
                    // 2. 复制到打包压缩的目录
                    if (file.exists()) {
                        log.info("fileZipTwo===> 打包的文件" + mf.getUrl());
                        try {
                            String thisZipPath = mf.getUrl().substring(ConstantUtil.FILE_PATH.length());
                            String thisZipDocPath = ConstantUtil.FILEZIP_PATH + thisZipPath;
                            if (file.isFile()) {
                                File thisZipPathParentDocument = new File(
                                        thisZipDocPath.substring(0, thisZipDocPath.lastIndexOf(File.separator)));
//								thisZipDocPath.substring(0, thisZipDocPath.lastIndexOf("/")));
                                if (!thisZipPathParentDocument.exists()) {
                                    thisZipPathParentDocument.mkdirs();// 创建压缩的父级文件夹
                                }
                                copyFile(file, new File(thisZipDocPath), null);
                            } else {
                                copyDirectiory(mf.getUrl(), thisZipDocPath, null);
                            }

                        } catch (Exception e) {
                            log.info("fileZipTwo===> 复制要打包的文件到压缩目录下方法报错:{}", e);
                            return null;
                        }
                    }
                }

                String zipRealPath = zipPath + ".zip";
                try {
                    ZipUtil.toZip(zipPath, new FileOutputStream(zipRealPath), true);
                } catch (Exception e) {
                    log.info("fileZip===> 调用压缩方法报错:{}", e);
                }

                mp = new MaterialPack();
                mp.setId(StringUtil.generatorUUID());
                mp.setPackname(mt.getCasename() + "-" + mt.getUploadpoliceid() + "-" + mt.getCasecode() + "（"
                        + mt.getCaseSuspectName() + "）");
                mp.setUrl(zipRealPath);
                mp.setCasecode(mt.getCasecode());
                mp.setPackpoliceid(mt.getUploadpoliceid());
                // 将压缩包文件信息存入数据库
                materialPackMapper.addMateriaPack(mp);// 添加打包信息
            }
        }
        return mp;
    }

    @Override
    public MaterialPackVo findAllMaterialPackInfoCount(String policeId) {
        if (StringUtil.isEmpty(policeId)) {
            return null;
        }
        return materialPackMapper.findAllMaterialPackInfoCount(policeId);
    }

    @Override
    public MaterialPack fileZipTwo2(String materialTypeId, String documentId) {
        MaterialPack mp = null;
        String filePath, fileZipPath, suspectNameDocPath, preZipPath = "", lastZipPath, zipPath, thisZipPath, randomFilename = StringUtil.generateRandomFilename();
        // 第一种情况：只有卷宗一级id
        if (!StringUtil.isEmpty(materialTypeId)) {
            String[] materialTypeIds = materialTypeId.split(",");
            List<MaterialType> mtList = mTypeMapper.findByIds(materialTypeIds);
            List<MaterialFile> mfList = mFileMapper.findFileByMaterialTypeIds(materialTypeIds);
            preZipPath = mtList.get(0).getCasename() + "-" + mtList.get(0).getUploadpoliceid() + "-" + mtList.get(0).getCasecode();
            lastZipPath = "（" + mtList.get(0).getCaseSuspectName() + "）";
            zipPath = ConstantUtil.FILEZIP_PATH + preZipPath + lastZipPath;
            suspectNameDocPath = mtList.get(0).getCaseSuspectName() + "/";
            for (MaterialType mt : mtList) {
                // 获取一级文件夹存放路径==》 案件名称-警员id-案件编号/嫌疑人姓名/一级目录名称
                thisZipPath = zipPath + File.separator + mt.getMaterialtypename() + File.separator;
                // 兼容win
                thisZipPath = thisZipPath.replace("\\", "/");
                // 1. 创建打包目录
                new File(thisZipPath).mkdirs();
            }

            for (MaterialFile materialFile : mfList) {
                // 2. 复制到打包压缩的目录
                log.info("fileZipTwo===> 打包的文件" + materialFile.getUrl());
                try {
                    thisZipPath = ConstantUtil.FILEZIP_PATH + preZipPath;
                    filePath = StringUtils.substringAfterLast(materialFile.getUrl(), ConstantUtil.XSKY_PREPATH_URL);
                    fileZipPath = filePath.replace(ConstantUtil.FILE_PATH.replace("\\", "/")
                            , ConstantUtil.FILEZIP_PATH.replace("\\", "/")).replace(thisZipPath.replace("\\", "/")
                            , zipPath.replace("\\", "/")).replace(suspectNameDocPath, "");
                    File file = new File(fileZipPath).getParentFile();
                    file.mkdirs();
                    xskyService.downloadObjectThrows(ConstantUtil.XSKY_BUCKET_DOSSIER, filePath, fileZipPath);
                } catch (Exception e) {
                    log.info("fileZipTwo===> xsky下载失败！:{}", e);
                    return null;
                }
            }

            // 3. 拼接压缩包的路径，并压缩
            String zipRealPath = zipPath + randomFilename + ZipUtil.FILE_TYPE;
            try {
                ZipUtil.toZip(zipPath, new FileOutputStream(zipRealPath), true);
            } catch (Exception e) {
                log.info("fileZip===> 调用压缩方法报错:{}", e);
            }

            // 4.上传到xsky存储
            try {
                // 兼容win
                zipRealPath = zipRealPath.replace("\\", "/");
                xskyService.uploadObjectThrows(ConstantUtil.XSKY_BUCKET_DOSSIER, zipRealPath, new File(zipRealPath));
            } catch (Exception e) {
                throw new RuntimeException(ResultEnum.XSKYUPLOADFAIL.getMsg(), e);
            }

            // 5.删除本地文件
            String finalZipRealPath = zipRealPath;
            String finalZipPath = zipPath;
            new Thread(() -> {
                ZipUtil.deleteFile(new File(finalZipPath));
                ZipUtil.deleteFile(new File(finalZipRealPath));
            }).start();

            // 6.将压缩包文件信息存入数据库
            mp = MaterialPack.builder().id(StringUtil.generatorUUID())
                    .packname(preZipPath + lastZipPath + randomFilename)
                    .url(ConstantUtil.XSKY_PREPATH_URL + zipRealPath).casecode(mtList.get(0).getCasecode()).packpoliceid(mtList.get(0)
                            .getUploadpoliceid()).build();
            materialPackMapper.addMateriaPack(mp);
        }
        // 第二种情况：只有卷宗二级文件夹id
        if (!StringUtil.isEmpty(documentId)) {
            String[] documentIds = documentId.split(",");
            List<MaterialFile> mfList = mFileMapper.findFileByDocumentIds(documentIds);
            List<MaterialTypeDocumentVo> mtdList = mTypeDocumentMapper.findDocPathByDocumentIds(documentIds);
            if (!CollectionUtils.isEmpty(mfList)) {
                // 1.压缩文件的路径
                preZipPath = mtdList.get(0).getCaseName() + "-"
                        + mtdList.get(0).getUploadPoliceId() + "-" + mtdList.get(0).getCaseCode();
                lastZipPath = "（" + mtdList.get(0).getCaseSuspectName() + "）";
                zipPath = ConstantUtil.FILEZIP_PATH + preZipPath + lastZipPath;
                suspectNameDocPath = mtdList.get(0).getCaseSuspectName() + "/";

                for (MaterialTypeDocumentVo mtdv : mtdList) {
                    // 获取文件夹存放路径==》 案件名称-警员id-案件编号/嫌疑人姓名/一级目录名称/文件夹名称
                    thisZipPath = zipPath + File.separator + mtdv.getMaterialTypeName() + File.separator + mtdv.getDocName() + File.separator;
                    // 兼容win
                    thisZipPath = thisZipPath.replace("\\", "/");
                    // 1. 创建打包目录
                    new File(thisZipPath).mkdirs();
                }

                for (MaterialFile mf : mfList) {
                    // 2. 复制到打包压缩的目录
                    log.info("fileZipTwo===> 打包的文件" + mf.getUrl());
                    try {
                        thisZipPath = ConstantUtil.FILEZIP_PATH + preZipPath;
                        filePath = StringUtils.substringAfterLast(mf.getUrl(), ConstantUtil.XSKY_PREPATH_URL);
                        fileZipPath = filePath.replace(ConstantUtil.FILE_PATH.replace("\\", "/")
                                , ConstantUtil.FILEZIP_PATH.replace("\\", "/")).replace(thisZipPath.replace("\\", "/")
                                , zipPath.replace("\\", "/")).replace(suspectNameDocPath, "");
                        File file = new File(fileZipPath).getParentFile();
                        file.mkdirs();
                        xskyService.downloadObjectThrows(ConstantUtil.XSKY_BUCKET_DOSSIER, filePath, fileZipPath);
                    } catch (Exception e) {
                        log.info("fileZipTwo===> xsky下载失败！:{}", e);
                        return null;
                    }
                }

                // 3. 拼接压缩包的路径，并压缩
                String zipRealPath = zipPath + randomFilename + ZipUtil.FILE_TYPE;
                try {
                    ZipUtil.toZip(zipPath, new FileOutputStream(zipRealPath), true);
                } catch (Exception e) {
                    log.info("fileZip===> 调用压缩方法报错:{}", e);
                }

                // 4.上传到xsky存储
                try {
                    // 兼容win
                    zipRealPath = zipRealPath.replace("\\", "/");
                    xskyService.uploadObjectThrows(ConstantUtil.XSKY_BUCKET_DOSSIER, zipRealPath, new File(zipRealPath));
                } catch (Exception e) {
                    throw new RuntimeException(ResultEnum.XSKYUPLOADFAIL.getMsg(), e);
                }

                // 5.删除本地文件
                String finalZipRealPath = zipRealPath;
                String finalZipPath = zipPath;
                new Thread(() -> {
                    ZipUtil.deleteFile(new File(finalZipPath));
                    ZipUtil.deleteFile(new File(finalZipRealPath));
                }).start();

                // 6.将压缩包文件信息存入数据库
                mp = MaterialPack.builder().id(StringUtil.generatorUUID())
                        .packname(preZipPath + lastZipPath + randomFilename)
                        .url(ConstantUtil.XSKY_PREPATH_URL + zipRealPath).casecode(mtdList.get(0).getCaseCode())
                        .packpoliceid(mtdList.get(0).getUploadPoliceId()).build();
                materialPackMapper.addMateriaPack(mp);
            }
        }
        return mp;
    }

}
